<?php /** @noinspection ALL */

/**
 * @author spenceryg
 * @date 2023/3/28
 * @time 7:06 上午
 * @focus love & life
 */

namespace app\task\controller;

use app\BaseController;
use app\common\lib\verify\AliSmsVerify;
use app\common\lib\verify\VerifyFactory;
use app\common\model\ApikeyLibrary;
use app\common\model\MemberFile;
use app\common\model\PushLog;
use app\common\model\PushPlan;
use hg\apidoc\annotation as Apidoc;
use app\common\model\ArticleContent;
use app\common\model\GptRequestLog;
use app\common\model\GptStrategy;
use app\common\model\GptToken;
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Response;
use think\facade\Db;

/**
 * Class Cron
 * @package app\api\controller
 *
 * @Apidoc\Title("定时任务")
 * @Apidoc\Group("api")
 */
class ArticleGenerateBaidu extends BaseController
{
    /**
     * 使用 AK，SK 生成鉴权签名（Access Token）
     * @return string 鉴权签名信息（Access Token）
     */
    private function getAccessToken($apikey,$secretkey){
        $curl = curl_init();
        $postData = array(
            'grant_type' => 'client_credentials',
            'client_id' => $apikey,
            'client_secret' => $secretkey
        );
        curl_setopt_array($curl, array(
            CURLOPT_URL => 'https://aip.baidubce.com/oauth/2.0/token',
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_SSL_VERIFYPEER  => false,
            CURLOPT_SSL_VERIFYHOST  => false,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POSTFIELDS => http_build_query($postData)
        ));
        $response = curl_exec($curl);
        curl_close($curl);
        $rtn = json_decode($response);
        return $rtn->access_token;
    }


    /**
     * @Apidoc\Title("按照最先提交生成")
     * 按照最先提交生成
     * createOld
     * @return string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function createArticlesOld(): string
    {
        $articles = \app\common\model\Article::where('state', 0)
            ->where('is_creating', '<',time()-600)
            ->order('article_title_task_id asc,create_time asc')
            ->limit(10)->select();
        //$articles = \app\common\model\Article::where('id', 164507)->limit(10)->select();
        if (!$articles->isEmpty()) {
            $this->doCreate($articles);
        }
        return 'success';
    }
    /**
     * doCreate
     * @param $articles
     * @return void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function doCreate($articles): void
    {
        //将文章设置为正在创作中的状态
        foreach ($articles as $article) {
            \app\common\model\Article::update([
                'id' => $article['id'],
                'is_creating' => time()
            ]);
        }

        $client = new Client();
        //创建一个 promises 数组，用于存储每个异步请求的 promise
        $promises = [];
        foreach($articles as $article){
            //获取提示词
            $strategy = GptStrategy::order('update_time', 'asc')->find();
            $strategy_name = $strategy['name'];
            $strategy->force()->save();
            //提示词
            $msg = str_replace('{title}', $article['name'], $strategy_name);
            $msg = str_replace('{length}', $article['length'], $msg);
            if($article['lang']){
                $msg.=" 生成语言为```{$article['lang']}```";
            }
            $msg.="。并且在文章最后一行给出关键词";
            //获取key
            $tokenModel = GptToken::where("category","百度AI")->orderRaw('rand()')->find();
            echo $tokenModel['token']."<br>";
            $tokenModel->force()->save();
            //

            $url="https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token={$this->getAccessToken($tokenModel['token'],$tokenModel['key2'])}";
            $promises[] = $client->postAsync($url, [
                    'verify' => false,
                    'headers' => [
                        'Content-Type' => 'application/json',
                    ],
                    'json' => [
                        'messages' => [
                            ['role' => 'user', 'content' => $msg]
                        ]
                    ]
            ])->then(
                function ($response) use ($article,$msg,$tokenModel) {
                    // 检查请求是否成功
                    if ($response->getStatusCode() == 200) {
                        // 获取响应的内容
                        $body = $response->getBody();
                        // 将JSON响应转换为数组（如果服务器返回的是JSON数据）
                        $result = json_decode($body);
                        //执行正确
                        if(isset($result->result)){
                            list($content, $keywords) = $this->extractKeywords($result->result);
                            //如果生成的内容小于100字，重新生成
                            if(mb_strlen($content)<100){
                                \app\common\model\Article::update([
                                    'id' => $article['id'],
                                    'is_creating' => 0
                                ]);
                                $gtpLog = [];
                                $gtpLog['name'] = $msg;
                                $gtpLog['prompt_tokens'] = -1;
                                $gtpLog['total_tokens'] = -1;
                                $gtpLog['completion_tokens'] = -1;
                                $gtpLog['member_id'] = $article['member_id'];
                                $gtpLog['gpt_token_id'] = $tokenModel['id'];
                                $gtpLog['article_id'] = $article['id'];
                                $gtpLog['reason_for_error'] = "生成文章字数少于100";
                                GptRequestLog::create($gtpLog);
                            }else{
                                //大于100字，可以记录好了
                                $gtpLog = [];
                                $gtpLog['name'] = $msg;
                                $gtpLog['prompt_tokens'] = $result->usage->prompt_tokens;
                                $gtpLog['total_tokens'] = $result->usage->total_tokens;
                                $gtpLog['completion_tokens'] = $result->usage->completion_tokens;
                                $gtpLog['member_id'] = $article['member_id'];
                                $gtpLog['gpt_token_id'] = $tokenModel['id'];
                                $gtpLog['article_id'] = $article['id'];
                                $gtpLog['reason_for_error'] = "";
                                GptRequestLog::create($gtpLog);
                                //更新文章
                                $state = 2;
                                if ($article['type'] == 1) {//如果type为1，说明用户设置了文章需要手动审核
                                    $state = 1;
                                }
                                \app\common\model\Article::update([
                                    'id' => $article['id'],
                                    'keywords'=>$keywords,
                                    'state' => $state
                                ]);
                                //文章内容处理
                                $content = $this->createHtml($content, $article['name']);
                                // 违禁词替换
                                if($article['forbiddenwords_id']){
                                    $content=$this->replaceForbiddenWords($content,$article['forbiddenwords_id']);
                                }
                                ArticleContent::where('article_id', $article['id'])->save(['name' => $content, 'update_time'=>time()]);
                            }
                        }else{
                            $gtpLog = [];
                            $gtpLog['name'] = $msg;
                            $gtpLog['prompt_tokens'] = -1;
                            $gtpLog['total_tokens'] = -1;
                            $gtpLog['completion_tokens'] = -1;
                            $gtpLog['member_id'] = $article['member_id'];
                            $gtpLog['gpt_token_id'] = $tokenModel['id'];
                            $gtpLog['article_id'] = $article['id'];
                            $gtpLog['reason_for_error'] =$result->error_msg;
                            GptRequestLog::create($gtpLog);
                        }
                    } else {
                        \app\common\model\Article::update([
                            'id' => $article['id'],
                            'is_creating' => 0
                        ]);
                        // 处理请求失败的逻辑
                        echo 'Request failed: ' . $response->getStatusCode() . "\n";
                    }
                },
                function ($reason) {
                    // 请求失败的处理逻辑
                    echo 'Request failed: ' . $reason . "\n";
                }
            );;
        }
        // 使用Promise\settle()等待所有异步请求完成
        $responses = Promise\settle($promises)->wait();
        echo "请求结束";exit;
    }

    //替换伪禁词
    private function replaceForbiddenWords($content,$forbiddenwords_id){
        if($forbiddenwords_id){
            $forbiddenwords = \app\common\model\ArticleForbiddenwords::find($forbiddenwords_id);
            $words = trim($forbiddenwords['content']);
            $arr = explode("\n", $words);
            $replace_arr = [];
            foreach ($arr as $replace){
                $this_replace = explode('=', $replace, 2);
                $key = $this_replace[0];
                $val = isset($this_replace[1])?$this_replace[1]:'';
                if(!$val){
                    $len = mb_strlen($key);
                    $val = str_repeat('*', $len);
                }
                $replace_arr[$key] = $val;
            }
            foreach ($replace_arr as $key => $val) {
                $content = str_replace($key, $val, $content);
            }
        }
        return $content;
    }

    //将内容创建为正式的html,便于发布
    private function createHtml($text,$title=""){
        $text=trim($text);
        $text=preg_replace('/^[\?\？]/u', '', $text);
        $text=trim($text);
        if($title){
            $title = preg_quote($title, '/');
            //echo $title;exit;
            //$text=preg_replace('#^'.$title.'#', '', $text);
            $text=preg_replace('/^'.$title.'$/m', "", $text);
            $text=preg_replace('/^标题：'.$title.'$/m', "", $text);
            $text=preg_replace('/^文章标题：'.$title.'$/m', "", $text);
            $text=preg_replace('/^title:'.$title.'$/m', "", $text);
            $text=preg_replace('/^《'.$title.'》/', '', $text);
            $text=preg_replace('/^<'.$title.'>/', '', $text);
        }
        //过滤掉每一行开头为：首先，其次，然后等这样的字符
        $repWord="首先,其次,然后,然而,再次,综上所述,总结一下，最后一下,总结,然而,同时,一方面,另一方面,因此,与此同时,总而言之,另外,总之,非常后,最后,此外";
        foreach(explode(",",$repWord) as $str){
            $text = preg_replace('/^'.$str.'[，,、.。：:\p{P}]*[\r\n]*/mu', '', $text);
        }
        //
        $lines = preg_split('/\r\n|\r|\n/', $text); // 将文本按行分割成数组
        $pattern = "/^(.*)$/m"; // 匹配每一行文本
        $replacement = "<p>$1</p>"; // 替换为带有<p>标签的文本
        $lines_with_tags = array_map(function($line) use ($pattern, $replacement) {
            if($line)return preg_replace($pattern, $replacement, $line); // 对每一行都增加<p>标签
        }, $lines);
        $text_with_tags = implode("\n", $lines_with_tags); // 将所有行拼接成一个字符串
        return $text_with_tags;
    }
    
    private function extractKeywords2($inputString) {
        // 将字符串按行拆分成数组
        $lines = explode("\n", $inputString);

        // 获取最后一行的内容
        $lastLine = array_pop($lines);

        // 将最后一行按 ":" 或 "：" 分割成数组
        $keywordsArray = preg_split('/[:：]/u', $lastLine, -1, PREG_SPLIT_NO_EMPTY);

        // 提取关键词字段
        if(isset($keywordsArray[1])){
            $keywords = $keywordsArray[1];
            $keywords = str_replace(['。', '.'], '', $keywords);
            $keywords = str_replace(['，', '、',' '], ',', $keywords);
            //对关键词过滤，要求每个关键词必须是2个中文以上，最多不能超过[5,8]个关键词
            $newkeywords=[];
            foreach(explode(",",$keywords) as $key=>$val){
                if(mb_strlen($val,'UTF-8')>2&&mb_strlen($val,'UTF-8')<15){
                    $newkeywords[]=$val;
                }
                if(count($newkeywords)>rand(5,8)){
                    break;
                }
            }
            $keywords=implode(",",$newkeywords);
        }else{
            $keywords="";
        }

        // 将数组重新组合成字符串
        $resultString = implode("\n", $lines);
        return array($resultString, $keywords);
    }
    //根据字符串提取文章内容和keywords
    private function extractKeywords($inputString) {
        // 将字符串按行拆分成数组
        $lines = explode("\n", $inputString);

        // 获取最后一行的内容
        $lastLine = array_pop($lines);

        // 将最后一行按 ":" 或 "：" 分割成数组
        $keywordsArray = preg_split('/[:：]/u', $lastLine, -1, PREG_SPLIT_NO_EMPTY);

        // 提取关键词字段
        if(isset($keywordsArray[1])){
            $keywords = $keywordsArray[1];
            $keywords = str_replace(['。', '.'], '', $keywords);
            $keywords = str_replace(['，', '、',' '], ',', $keywords);
            //对关键词过滤，要求每个关键词必须是2个中文以上，最多不能超过[5,8]个关键词
            $newkeywords=[];
            foreach(explode(",",$keywords) as $key=>$val){
                if(mb_strlen($val,'UTF-8')>2&&mb_strlen($val,'UTF-8')<15){
                    $newkeywords[]=$val;
                }
                if(count($newkeywords)>rand(5,8)){
                    break;
                }
            }
            $keywords=implode(",",$newkeywords);
        }else{
            $keywords="";
        }

        // 将数组重新组合成字符串
        $resultString = implode("\n", $lines);
        return array($resultString, $keywords);
    }

}
